import markdownit from "markdown-it";
import container from "markdown-it-container";
import { vsprintf } from "sprintf-js";
import { readFileSync, writeFileSync } from "node:fs";

let fileContent = readFileSync("./src/md/index.mdx", { encoding: "utf-8" });

const template = `
import React from "react";
import Scene from "../components/Scene";
import Prism from "../components/Prism";
import Sql from "../components/Sql";
import Slide from "../components/Slide";

export function getScenes(setter: any) {
    return %s;
}
`;

function prism(md) {
    md.renderer.rules.fence = (...args) => {
        const [tokens, idx] = args;
        const token = tokens[idx];
        return `<Prism code={\`${token.content.replace(/`/g, "\\`")}\`} lang="${
            token.info
        }" onAnnotationChange={(content: any) => setter(content)}/>`;
    };
}

function annotation(md) {
    const proxy = (tokens, idx, options, env, self) =>
        self.renderToken(tokens, idx, options);
    const paragraph_open = md.renderer.rules.paragraph_open || proxy;
    md.renderer.rules.paragraph_open = function (...args) {
        const [tokens, idx] = args;
        const nextToken = tokens[idx + 1];
        if (nextToken.content.indexOf("==") === 0) {
            return "";
        }
        if (nextToken.content.indexOf("L") === 0) {
            return `<div className="annotation">`;
        }
        if (nextToken.content.indexOf("<Sql") === 0) {
            return `<div>`;
        }
        return paragraph_open(...args);
    };
    md.renderer.rules.paragraph_close = function (...args) {
        const [tokens, idx] = args;
        const prevToken = tokens[idx - 1];
        if (prevToken.content.indexOf("==") === 0) {
            return "";
        }
        if (prevToken.content.indexOf("L") === 0) {
            return `</div>`;
        }
        if (prevToken.content.indexOf("<Sql") === 0) {
            return `</div>`;
        }
        return paragraph_open(...args);
    };
    const text = md.renderer.rules.text;
    md.renderer.rules.text = (...args) => {
        const [tokens, idx] = args;
        const token = tokens[idx];
        const pattern = /L(\d+)\-\>/;
        if (pattern.test(token.content)) {
            const m = token.content.match(pattern);
            let content = token.content.replace(pattern, "");
            if (!/\<.*?\>/.test(token.content)) {
                content = `<div className="text-3xl">${content}</div>`;
            }
            return `<div className="hidden" data-line="${m[1]}">${content}</div>`;
        }
        return text(...args);
    };
}

function textPlugin(md) {
    const text = md.renderer.rules.text;
    md.renderer.rules.text = (...args) => {
        const [tokens, idx] = args;
        const token = tokens[idx];
        if (token.content.indexOf("==") === 0) {
            let content = token.content
                .trim()
                .replace("== ", "")
                .split(/[。？]/)
                .filter((value) => value !== "")
                .map((value) => ({
                    content: value,
                }));
            console.log(content);
            return "<Slide items={" + JSON.stringify(content) + "}/>";
        }
        return text(...args);
    };
}

const md2 = markdownit({
    html: true,
});
md2.use(textPlugin);
// console.log(md2.parseInline("<Sql data={[{records: 1}]}/>", {}));

const md = markdownit({
    html: true,
})
    .use(textPlugin)
    .use(prism)
    .use(annotation)
    .use(container, "code", {
        validate: function (params) {
            return params.trim().match(/^code/);
        },
        render: function (tokens, idx) {
            if (tokens[idx].nesting === 1) {
                return "<Code>";
            } else {
                return "</Code>";
            }
        },
    })
    .use(container, "scene", {
        validate: function (params) {
            return params.trim().match(/^scene/);
        },
        render: function (tokens, idx) {
            const info = tokens[idx].info;
            const subject = info.trim().match(/^scene\s+subject$/);
            const link = info.trim().match(/^scene\s+link\s+(.*)\s+(.*)$/);
            const code = info.trim().match(/^scene\s+code\s+(.*)$/);
            const m = info.trim().match(/^scene\s+(.*)$/);

            if (tokens[idx].nesting === 1) {
                // opening tag
                if (subject) {
                    let titleToken;
                    let subTitleToken;
                    for (let i = 0; i < tokens.length; i++) {
                        const token = tokens[i];
                        if (
                            token.type === "container_scene_open" &&
                            token.info.trim() === "scene subject"
                        ) {
                            titleToken = tokens[i + 2];
                            subTitleToken = tokens[i + 5];
                        }
                    }
                    return (
                        '<Scene type="subject" title="' +
                        titleToken.content +
                        '" subTitle="' +
                        subTitleToken.content +
                        '">\n'
                    );
                } else if (link) {
                    return (
                        '<Scene type="link" title="' +
                        link[1] +
                        '" link="' +
                        link[2] +
                        '">\n'
                    );
                } else if (code) {
                    return '<Scene type="code" title="' + code[1] + '">\n';
                } else if (m) {
                    return '<Scene type="basic" title="' + m[1] + '">\n';
                } else {
                    return "<Scene>\n";
                }
            } else {
                // closing tag
                return "</Scene>|||\n";
            }
        },
    });

let result = md.render(fileContent);

const scenes = result.substring(0, result.length - 4).split("|||");

writeFileSync(
    "./src/md/index.tsx",
    vsprintf(template, [
        "[" +
            scenes
                .map((scene, index) => {
                    let enabled = "false";
                    if (index === 0) {
                        enabled = "true";
                    }
                    return (
                        "{ start: 0, end: 0, enabled: " +
                        enabled +
                        ", component: " +
                        scene +
                        " }"
                    );
                })
                .join(",") +
            "]",
        "[" + result.substring(0, result.length - 2) + "]",
    ])
);
